package com.sunmouse.toolkit.fragment.camera;


import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;

import com.sunmouse.toollib.utils.LogUtils;
import com.sunmouse.toolkit.R;
import com.sunmouse.toolkit.fragment.BaseFragment;

import java.util.Arrays;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;

/**
 * A simple {@link Fragment} subclass.
 * <p>
 * <span>how to use camera2 </span>
 * >1.打开CameraDevice;
 * >2.设置预览对话;
 * >3.提交预览session (capture提交--用于拍照;setRepeatingRequest提交--用于持续预览)
 * </p>
 * <p/>
 * <p>
 * <sapn> take photo:</sapn>
 * >1.在创建CaptureSession时添加多个Surface,一个用于预览(SurfaceView的surface)，一个用于存储Image(ImageReader的Surface)
 * >2.通过ImageReader来保存图片实现take photo功能
 * </p>
 */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class Camera2Fragment extends BaseFragment {

    public static final String TAG = "Camera2";

    @BindView(R.id.m_surface)
    TextureView mSurface;
    Unbinder unbinder;

    private CameraManager mCameraManager;
    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;
    private String mCameraId;
    private CaptureRequest.Builder mCaptureBuilder;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_camera2, container, false);
        unbinder = ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void init() {
        this.mCameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);

        this.mSurface.setSurfaceTextureListener(mTextureListener);
    }


    @Override
    public void onResume() {
        super.onResume();
        startBackgroundThread();
    }

    /**
     * texture listener
     */
    private TextureView.SurfaceTextureListener mTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            openCamera();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };

    /**
     * open camera
     */
    private void openCamera() {
        this.mCameraId = getCameraId();
        if (TextUtils.isEmpty(mCameraId)) return;
        try {
            if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            mCameraManager.openCamera(mCameraId, mStateCk, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * camera device callback
     */
    private CameraDevice.StateCallback mStateCk = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(CameraDevice camera) {
            LogUtils.i(TAG, "camera prepared...");
            initPreviewSession(camera);
        }

        @Override
        public void onDisconnected(CameraDevice camera) {

        }

        @Override
        public void onError(CameraDevice camera, int error) {

        }
    };

    /**
     * init preview session
     *
     * @param cameraDevice
     */
    private void initPreviewSession(final CameraDevice cameraDevice) {
        try {
            SurfaceTexture texture = mSurface.getSurfaceTexture();
            if (texture == null) return;
            texture.setDefaultBufferSize(400, 400);
            Surface surface = new Surface(texture);

            mCaptureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mCaptureBuilder.addTarget(surface);
            cameraDevice.createCaptureSession(Arrays.asList(surface), mCaptureStateCk, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * private
     */
    private CameraCaptureSession.CaptureCallback mCpCk = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {
            super.onCaptureProgressed(session, request, partialResult);
        }

        @Override
        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
        }
    };

    /**
     * camera capture state ck
     */
    private CameraCaptureSession.StateCallback mCaptureStateCk = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {
            try {
                //init auto focus and auto flash
                mCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                mCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

                CaptureRequest mRequest = mCaptureBuilder.build();
                session.setRepeatingRequest(mRequest, mCpCk, mHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {
            LogUtils.i(TAG, "-------failure...");

        }
    };

    /**
     * find camera Id
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private String getCameraId() {
        try {
            for (String cameraId : mCameraManager.getCameraIdList()) {
                CameraCharacteristics cha = mCameraManager.getCameraCharacteristics(cameraId);
                if (cha.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT)
                    return cameraId;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";

    }

    /**
     * Starts a background thread and its {@link Handler}.
     */
    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    /**
     * Stops the background thread and its {@link Handler}.
     */
    private void stopBackgroundThread() {
        if (mBackgroundThread != null) {
            mBackgroundThread.quitSafely();
            try {
                mBackgroundThread.join();
                mBackgroundThread = null;
                mBackgroundHandler = null;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public void onPause() {
        stopBackgroundThread();
        closeCamera();
        super.onPause();
    }

    /**
     * close camera
     */
    private void closeCamera() {

    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
//        stopBackgroundThread();
        unbinder.unbind();
    }
}
